using System;
using System.Collections.Generic;
using System.Text;

namespace TeamTasker.Utils {
    /// <summary>
    /// Represents utils methods for generic Lists.
    /// </summary>
    public class ListUtils {

        /// <summary>
        /// Checks equality of two lists by sorting both and comparing values.
        /// </summary>
        /// <typeparam name="T">Parameter type.</typeparam>
        /// <param name="list1"></param>
        /// <param name="list2"></param>
        /// <returns>True if both lists are equal.</returns>
        public static bool Equals<T>(IList<T> list1, IList<T> list2)
        {
            if (list1 == list2)
            {
                return true;
            }
            if (list1 == null || list2 == null || list1.Count != list2.Count)
            {
                return false;
            }
            SortList(list1);
            SortList(list2);
            for (int i = 0; i < list1.Count; i++)
            {
                T str1 = list1[i];
                T str2 = list2[i];
                if (str1.Equals(default(T)) || str2.Equals(default(T)) || !(str1.Equals(str2)))
                {
                    return false;
                }
            }
            return true;
        }

        [Obsolete("Remove, because there is method CopyTo that copy elements to an array.")]
        public static T[] ToArray<T>(IList<T> list)
        {
            if (list == null)
            {
                throw new NullReferenceException("Can't handle null list.");
            }
            T[] result = new T[list.Count];
            int i = 0;
            foreach (T item in list)
            {
                result[i++] = item;
            }
            return result;
        }

        public static List<T> RemoveDuplicates<T>(IList<T> list)
        {
            Dictionary<T, int> uniqueStore = new Dictionary<T, int>();
            List<T> finalList = new List<T>();
            int i = 0;
            foreach (T currValue in list)
            {
                if (!uniqueStore.ContainsKey(currValue))
                {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(list[i]);
                }
                i++;
            }
            return finalList;
        }

        public static IList<T> Merge<T>(IList<T> list1, IList<T> list2)
        {
            bool list1empty = IsNullOrEmpty(list1);
            bool list2empty = IsNullOrEmpty(list2);

            IList<T> result;
            if (list1empty && list2empty)
            {
                result = new List<T>();
            }
            else if (!list1empty && list2empty)
            {
                result = new List<T>(list1);
            }
            else if (list1empty)
            {
                result = new List<T>(list1);
            }
            else // both lists are non-empty
            {
                List<T> dst = new List<T>(list1);
                dst.AddRange(list2);
                result = dst;
            }
            return result;
        }

        public static bool EqualsTo<T>(IList<T> list, T pattern)
        {
            if (IsNullOrEmpty(list) || pattern.Equals(default(T)))
            {
                return false;
            }
            foreach (T str in list)
            {
                if (str.Equals(default(T)) || !(str.Equals(pattern)))
                {
                    return false;
                }
            }
            return true;
        }
        
        public static bool EqualsIgnoreCaseTo(IList<string> list, string pattern)
        {
            if (IsNullOrEmpty(list) || pattern == null)
            {
                return false;
            }
            foreach (string str in list)
            {
                if (str == null || !(str.ToUpper().Equals(pattern.ToUpper())))
                {
                    return false;
                }
            }
            return true;
        }

        public static void SortList<T>(IList<T> list)
        {
            ((List<T>)list).Sort();
        }

        public static bool IsNullOrEmpty<T>(ICollection<T> coll)
        {
            if (coll == null || coll.Count == 0)
            {
                return true;
            }

            return false;
        }
        
        public static IList<int> ConvertToInt(IList<string> list) {
            if (list == null) {
                throw new NullReferenceException("Can't convert IList<string> to IList<int>, because list is null.");
            }
            IList<int> result = new List<int>();
            foreach (string s in list) {
                int i;
                if (string.IsNullOrEmpty(s) || !int.TryParse(s, out i)) {
                    throw new NullReferenceException(
                        "Can't convert IList<string> to IList<int>, because string element is null.");
                }
                result.Add(i);
            }
            return result;
        }

        public static IList<string> ConvertToString(IList<int> list) {
            if (list == null) {
                throw new NullReferenceException("Can't convert IList<int> to IList<string>, because list is null.");
            }
            IList<string> result = new List<string>();
            foreach (int i in list) {
                result.Add(i.ToString());
            }
            return result;
        }

        public static IList<bool> ConvertToBoolean(IList<int> list)
        {
            if (list == null)
            {
                throw new NullReferenceException("Can't convert IList<string> to IList<int>, because list is null.");
            }
            IList<bool> result = new List<bool>();
            foreach (int i in list)
            {
                result.Add(Convert.ToBoolean(i));
            }
            return result;
        }

        public static IList<DateTime> ConvertToDateTime(IList<string> list)
        {
            if (list == null)
            {
                throw new NullReferenceException("Can't convert IList<string> to IList<DateTime>, because list is null.");
            }
            IList<DateTime> result = new List<DateTime>();
            foreach (string dateTime in list)
            {
                // If string is emtpy than to avoid exception it must ne null - in this case 
                // Convert.ToDateTime will return DateTime.MinValue.
                string tempDateTime = StringUtils.EmptyToNull(dateTime);
                result.Add(Convert.ToDateTime(tempDateTime));
            }
            return result;
        }

        /// <summary>
        /// Returns value by specified index or default value if there is no such.
        /// </summary>
        /// <typeparam name="T">Parameter type.</typeparam>
        /// <param name="list">List to get value from.</param>
        /// <param name="counter">Index to get value by.</param>
        /// <returns>Value by specified index or default value if there is no such.</returns>
        public static T GetValueOrDefault<T>(IList<T> list, int counter)
        {
            T result = default(T);
            if (!IsNullOrEmpty(list) && counter < list.Count)
            {
                result = list[counter];
            }
            return result;
        }
        
        /// <summary>
        /// Returns DateTime value by specified index or DateTime.MinValue if there is no such.
        /// </summary>
        /// <param name="list">List to get value from.</param>
        /// <param name="counter">Index to get value by.</param>
        /// <returns>DateTime value by specified index or DateTime.MinValue if there is no such.</returns>
        public static DateTime GetValueOrDefault(IList<DateTime> list, int counter)
        {
            DateTime result = DateTime.MinValue;
            if (!IsNullOrEmpty(list) && counter < list.Count)
            {
                result = list[counter];
            }
            return result;
        }

        /// <summary>
        /// Joins all elements of a list as strings and returns result
        /// as a single string. 
        /// </summary>
        /// <typeparam name="T">list items type</typeparam>
        /// <param name="list">list to join</param>
        /// <param name="separator">separator to use between list items, e.g. ","</param>
        /// <returns>joined list items as string with separators</returns>
        public static string Join<T>(IList<T> list, string separator)
        {
            StringBuilder dst = new StringBuilder("[");
            for (int i = 0; i < list.Count; ++i)
            {
                T t = list[i];
                if (t == null)
                {
                    dst.Append("null");
                }
                else
                {
                    dst.Append(t.ToString());
                }
                if (i < list.Count - 1)
                {
                    dst.Append(separator);
                }
            }
            return dst.Append("]").ToString();
        }
    }
}